﻿/*************************************************************************
* Copyright(c) 2020 - Present ShenZhen EscopeTech

* ShenZhen EscopeTech Incoperated CONFIDENTIAL
* ________________________________________________________________________
*
* [2020] - Present ShenZhen EscopeTech Incoperated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of ShenZhen EscopeTech Incoperated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to ShenZhen EscopeTech Incoperated
* and its suppliers and may be covered by P.R.C. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from ShenZhen EscopeTech Incoperated.
*
*************************************************************************/

#ifndef PUBFUNXA_H
#define PUBFUNXA_H

#include <QDebug>
#include <QFileInfo>
#include <QJsonArray>
#include <QJsonObject>
#include <QLineEdit>
#include <QPolygonF>
#include <QRect>
#include <QStringList>
#include <QStyle>
#include <algorithm>
#include <functional>
#include <string>
#include <vector>

template <typename _Container>
struct XACheckContainer
{
    template <typename T, typename T::size_type (T::*)(void) const = &T::size>
    static constexpr bool isContainer(T*)
    {
        return true;
    }
    static constexpr bool isContainer(...) { return false; }
    static constexpr bool value = isContainer(static_cast<_Container*>(0));
};

class DUtils
{
public:
    DUtils();

public:
    template <template <typename E> class _container, typename _type>
    static QString toSizeString(const _container<_container<_type>>& container)
    {
        return std::accumulate(
            container.begin(), container.end(), QString("Size: "),
            [](const QString& str, const _container<_type>& l)
            { return str + QString("%1 ").arg(l.size()); });
    }

    static void clearLayout(QLayout* hLayout);
    static void mergeVecInt(std::vector<int>& vecOld,
                            const std::vector<int>& vecNew);

    static void mergeVecInt(std::vector<int>& vecOld, int nVecNew);

    static QString toHexColor(int nR, int nG, int nB);

    template <template <typename E, class _Alloc = std::allocator<E>>
              class _container,
              typename _type>
    static QString toSizeStringSTD(
        const _container<_container<_type>>& container)
    {
        return std::accumulate(
            container.begin(), container.end(), QString("Size: "),
            [](const QString& str, const _container<_type>& l)
            { return str + QString("%1 ").arg(l.size()); });
    }

    template <template <typename E, class _Alloc = std::allocator<E>>
              class _container = std::vector,
              typename T>
    static _container<T> listMultiSTD(const _container<T>& list, double dRate)
    {
        _container<T> ret;
        std::transform(list.begin(), list.end(), std::back_inserter(ret),
                       [dRate](T t)
                       {
                           t *= dRate;
                           return t;
                       });

        return ret;
    }

    template <typename T,
              template <typename E, class _Alloc = std::allocator<E>>
              class _container = std::vector>
    static _container<T> toListSTD(const QJsonArray& jar)
    {
        _container<T> listRet;
        QVariantList varList = jar.toVariantList();
        std::transform(varList.constBegin(), varList.constEnd(),
                       std::back_inserter(listRet),
                       [](const QVariant& var) { return var.value<T>(); });
        return listRet;
    }

    template <typename T, template <typename E> class _container>
    static _container<T> toListQT(const QJsonArray& jar)
    {
        _container<T> listRet;
        QVariantList varList = jar.toVariantList();
        std::transform(varList.constBegin(), varList.constEnd(),
                       std::back_inserter(listRet),
                       [](const QVariant& var) { return var.value<T>(); });
        return listRet;
    }

    template <typename T,
              template <typename E, class _Alloc = std::allocator<E>>
              class _container = std::vector>
    static QJsonArray fromListSTD(const _container<T>& list)
    {
        QJsonArray jarRet;
        std::transform(list.begin(), list.end(), std::back_inserter(jarRet),
                       [](const T v) { return v; });
        return jarRet;
    }

    template <typename T, template <typename E> class _container>
    static QJsonArray fromList(const _container<T>& list)
    {
        QJsonArray jarRet;
        std::transform(list.begin(), list.end(), std::back_inserter(jarRet),
                       [](const T v) { return v; });
        return jarRet;
    }

    static bool greaterEqual(const double& a, const double& b)
    {
        return a > b || std::fabs(a - b) < 1e-8;
    }

    static bool equal(const double& a, const double& b)
    {
        return std::fabs(a - b) < 1e-8;
    }

    static bool lessEqual(const double& a, const double& b)
    {
        return a < b || std::fabs(a - b) < 1e-6;
    }

    static QString createNewUUID();

    template <typename From, typename To>
    static QList<To> typeChange(const QList<From>& vecFrom)
    {
        QList<To> vecRet;

        std::copy(vecFrom.begin(), vecFrom.end(), std::back_inserter(vecRet));

        return vecRet;
    }

    template <typename From, typename To,
              template <typename E, class _Alloc = std::allocator<E>>
              class _container>
    static _container<To> typeChangeSTD(const _container<From>& vecFrom)
    {
        _container<To> vecRet;

        std::copy(vecFrom.begin(), vecFrom.end(), std::back_inserter(vecRet));

        return vecRet;
    }

    static bool checkIndexRange(const int& nMax,
                                const std::initializer_list<int>& list);
    static bool checkIndexRange(const int& nMax, const int& nIndex);

    template <typename T,
              std::enable_if_t<XACheckContainer<T>::value, T>* = nullptr>
    static bool checkIndexRangeT(const T& t, const int& nIndex)
    {
        return checkIndexRange(t.size(), nIndex);
    }

    static void setStyleSheet(QWidget* wgt, const QString& strFileName);
    static void updateStyle(QWidget* wdg);

    // File
    static std::vector<QFileInfo> getFilesWithRegExp(const QString& strFolder,
                                                     const QString& strRegExp);

    static QStringList getFilePathWithRegExp(const QString& strFolder,
                                             const QString& strRegExp);

    static void setAppCSSStyle(const QString& strCSS);

    static QString readFile(const QString& strFile);
    static std::vector<QFileInfo> findFiles(const QString& strDir);
    static void makeDir(const QString& strDir);
    static void makeEmptyDir(const QString& strDir);
    static void makeDir(const std::initializer_list<QString>& listDir);
    static void makeDirWithFileName(const QString& strFileName);
    static bool removeDir(const QString& path, bool isRecursion = true);
    static bool clearDir(const QString& strDirName, bool bRemove = false);
    static bool removeFile(const QString& strFileName);
    static bool copyFilesToDir(const QStringList& listSrc,
                               const QString& strDirDest);

    static bool copyFilesOfDirectory(const QString& fromDir,
                                     const QString& toDir,
                                     bool coverFileIfExist);

    static bool copyFile(const QString& strSrc, const QString& strDest);
    static QString getFileName(const QString& strFile);
    static QString getUpDirName(const QString& strFile);
    static QString getUpDirPath(const QString& strFile);
    // for json
    static QJsonObject stringtoObject(const QString& strJson);
    static QJsonArray stringToArray(const QString& strJson);
    static QString jsonToString(const QJsonObject& json);
    static QJsonObject readJsonFromFile(const QString& strFile);
    static QJsonArray readJsonArrayFromFile(const QString& strFile);
    static QJsonValue jsonGetValue(const QJsonObject& json,
                                   const QString& strPath);
    static void writeJsonToFile(const QString& strJsonFile,
                                const QJsonObject& jsonData);
    static void writeJsonArrayToFile(const QString& strJsonFile,
                                     const QJsonArray& jarData);

    // reflex
    template <typename T>
    static QString reflexToString(const T& t)
    {
        const QMetaEnum metaEnum = QMetaEnum::fromType<T>();
        return metaEnum.valueToKey(t);
    }

    template <typename T>
    static QStringList reflexToStringList(const quint64& t)
    {
        const QMetaEnum metaEnum = QMetaEnum::fromType<T>();
        QStringList listRet;
        for (int i = 0; i < metaEnum.keyCount(); ++i)
        {
            if (t & metaEnum.value(i))
            {
                listRet << metaEnum.key(i);
            }
        }
        return listRet;
    }

    template <typename T>
    static T reflexFromString(const QString& str)
    {
        const QMetaEnum metaEnum = QMetaEnum::fromType<T>();
        return static_cast<T>(metaEnum.keysToValue(str.toUtf8().data()));
    }

    template <typename T>
    static qint64 reflexFromStringList(const QStringList& list)
    {
        qint64 nRet = 0x00;
        std::for_each(list.begin(), list.end(),
                      [&nRet](const QString& s)
                      { nRet |= static_cast<qint64>(reflexFromString<T>(s)); });
        return nRet;
    }
};

#endif  // PUBFUNXA_H
